/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.p4;

import com.example.p4.R;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Handler;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.Window;

/**
 * Snake: a simple game that everyone can enjoy.
 * 
 * This is an implementation of the classic Game "Snake", in which you control a
 * serpent roaming around the garden looking for apples. Be careful, though,
 * because when you catch one, not only will you become longer, but you'll move
 * faster. Running into yourself or the walls will end the game.
 * 
 */
public class FallingBalls extends Activity {

    private FallingBallsView mGameView;
    
    public static final int PAUSE = 0;
    public static final int READY = 1;
    public static final int RUNNING = 2;
    public static final int LOSE = 3;
    public static final int WIN = 4;
    protected static int mMode = READY;
    
    protected int titleBarHeight = -1;
    
    private long endTime = 0;

    /**
     * Called when Activity is first created. Turns off the title bar, sets up
     * the content views, and fires up the SnakeView.
     * 
     */
    @Override
    public void onStart() {
        super.onStart();
        
        //Testing functionality of app before trying to execute
        //To prevent in-app crashes
        try{
        	testFunctionality();
        }catch(Exception e)
        {
        	Log.e("Error!", "Error occured during testing of functionality of Maze");
        	finish();
        }
        
        setContentView(R.layout.falling_balls_layout);
        mGameView = (FallingBallsView) findViewById(R.id.falling_balls_game_layout);
        mGameView.resetGame();
        
    	DisplayMetrics metrics = new DisplayMetrics();
    	getWindowManager().getDefaultDisplay().getMetrics(metrics);

    	mGameView.setScreenResolution(metrics.heightPixels, metrics.widthPixels);
        
        doTheAutoRefresh();
    }
    
    @Override
    public void onPause()
    {
    	mGameView.resetGame();
    	mMode = READY;
    	recycleMemory();
    	System.gc();
    	super.onPause();
    }
    
    private void recycleMemory()
    {
    	if(mGameView != null && mGameView.images != null)
    		for(int i=0; i<mGameView.images.length; i++)
    		{
    			if(mGameView.images[i] != null)
    				mGameView.images[i].recycle();
    		}
    }
    
    private void testFunctionality() throws Exception
    {
    	try{
    		getTitleBarHeight();
    	}
    	catch(Exception e)
    	{
    		throw new Exception("getTitleBarHeight() returned an invalid value");
    	}
    }
    
    private int getTitleBarHeight()
    {
    	Rect rectangle= new Rect();
    	Window window= getWindow();
    	window.getDecorView().getWindowVisibleDisplayFrame(rectangle);
    	int StatusBarHeight= rectangle.top;
    	int contentViewTop= 
    	    window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
    	int TitleBarHeight= StatusBarHeight - contentViewTop;
    	return TitleBarHeight;
    }
    
    public void startGame()
    {
    	mGameView.initNewGame(5);
   	 	endTime = System.currentTimeMillis() + 4600;
   	 	
        setMode(RUNNING);
    }
    
    public void setScore(double score)
    {
    	Intent data = new Intent();
    	data.putExtra("score", (double)score);
    	
    	if (getParent() == null) {
    	    setResult(Activity.RESULT_OK, data);
    	} else {
    	    getParent().setResult(Activity.RESULT_OK, data);
    	}
    }
    
    public void invokeWin()
    {
    	Log.d("GameEvent", "Game Won!");
    	setScore(30);
    	setWinScreen();
    	stopActivity();
    }
    
    public void invokeLoss()
    {
    	Log.d("GameEvent", "Game Loss...");
    	setScore(0);
    	setLoseScreen();
    	stopActivity();
    }
    
    public void stopActivity()
    {
    	Log.d("GameEvent", "Stopping activity");
    	finish();
    }
    
    private void setWinScreen()
    {
    	mGameView.setMode(FallingBallsView.MODE_WIN);
    	mGameView.invalidate();
    }
    private void setLoseScreen()
    {
    	mGameView.setMode(FallingBallsView.MODE_LOSE);
    	mGameView.invalidate();
    }
    
    public void setMode(int newMode) {
        mMode = newMode;
    }

    private void checkWin()
    {
    	if(mGameView.balls.size() == 0)
    		setMode(WIN);
    }
    
    private void checkLose()
    {
    	if(endTime-System.currentTimeMillis() < -100)
    		setMode(LOSE);
    }
    
    
    @Override
    public boolean onTouchEvent(MotionEvent e) {
        // MotionEvent reports input details from the touch screen
        // and other input controls. In this case, you are only
        // interested in events where the touch position changed.
    	
    	if(titleBarHeight == -1)
    	{
    		titleBarHeight = getTitleBarHeight();
    	}

        switch(e.getAction())
        {
	        case MotionEvent.ACTION_DOWN:
	        	onDownClick(e);
	        	break;
	        case MotionEvent.ACTION_MOVE:
	        	//onDrag(e);
	        	break;
	        default:
	        	//Log.d("MouseEvent", "Unkown mouseEvent");
	        	break;
        }
        
        if(mMode == RUNNING)
        	checkWin();
        
        return true;
    }
    
    public void onDownClick(MotionEvent e)
    {
    	int x = (int)e.getX();
    	int y = (int)e.getY();
    	
    	int ballWidth = mGameView.getBallWidth();
    	int ballHeight = mGameView.getBallHeight();
    	
    	//mGameView.addTouchPoint(x, y);
    	for(int i=mGameView.balls.size()-1; i>= 0; i--)
    	{
    		if(x > mGameView.balls.get(i).x && x < mGameView.balls.get(i).x+ballWidth 
    		&& y > mGameView.balls.get(i).y && y < mGameView.balls.get(i).y+ballHeight)
    		{
    			mGameView.balls.remove(i);
    			break;
    		}
    	}
    }
    
    public void onDrag(MotionEvent e)
    {
    	int x = (int)e.getX();
    	int y = (int)e.getY();
    	
    	mGameView.addTouchPoint(x, y);
    }
    
    

    public void update() {
		updateProgressBar();
		updateBalls();
		mGameView.updateTrail();
        mGameView.invalidate();
    }
    
    private void updateBalls()
    {
    	for(int i=0; i<mGameView.balls.size(); i++)
    	{
    		//Change Ball Positions
    		mGameView.balls.get(i).move(0, 0, mGameView.screenWidth-mGameView.getBallWidth(), mGameView.screenHeight-mGameView.getBallHeight());
    	}
    }
    
    private void updateProgressBar()
    {
    	mGameView.progressBarPercent = ((double)(endTime-System.currentTimeMillis()))/4600;
    }
    
    private final static Handler handler = new Handler();
    
    private void doTheAutoRefresh() {
        handler.post(new Runnable() {
             public void run() {
        		 if(mMode == READY)
        			 startGame();
        		 else if (mMode == RUNNING)
        		 {
        			 update(); // this is where you put your refresh code
        		 	 checkLose();
        		 }
        		 else if(mMode == WIN){
        			 invokeWin();
        			 return;
        		 }
        		 else if (mMode == LOSE){
        			 invokeLoss();
        			 return;
        		 }
                 doTheAutoRefresh();                
             }
         });
    }
}
